/*
 * DNSService.cpp
 *
 *  Created on: Dec 12, 2013
 *      Author: m
 */

#include <iostream>
#include <fstream>
#include <rpc/rpc.h> /* always needed */
#include "AgentAddressCommon.h"
#include "AgentAddressService.h"
#include "../../IPC/Sequence.h"
#include "../../common/Exception.h"
#include "../../common/ArchivoIni.h"
#include <unistd.h>

namespace channel{

const char* AgentAddressService::getServerAddress()
{
    static std::string serverAddress;
    if ( serverAddress.empty() )
    {
        //Get the RPC server address from config file
    	MapaIni config = ArchivoIni::parsearComoIni("config.ini");

        serverAddress = config["agent_address_server"];

        if ( serverAddress.empty() )
            throw Exception( "Agent address ERROR: Server address not found!" );
    }
    return serverAddress.c_str();
}

CLIENT* AgentAddressService::createClient()
{
	CLIENT* cl;

	//Create client "handle" used for calling MESSAGEPROG on the
	//server designated on the command line. We tell the RPC package
	//to use the "tcp" protocol when contacting the server.

	cl = clnt_create( getServerAddress(), AGENT_ADDRESS_PROG, AGENT_ADDRESS_VERS, "tcp" );

	//Couldn’t establish connection with server.
	//Print error message and die.
	if ( cl == NULL )
		throw Exception( clnt_spcreateerror( getServerAddress() ) );

	return cl;
}

void AgentAddressService::create()
{
	ipc::Sequence::create(AGENT_ADDRESS_SEQ_PATH,AGENT_ADDRESS_SEQ_KEY);
}

void AgentAddressService::destroy()
{
	ArchivoTexto::borrarArchivo(AGENT_ADDRESS_FILE);
	ipc::Sequence::destroy(AGENT_ADDRESS_SEQ_PATH,AGENT_ADDRESS_SEQ_KEY);
}

int AgentAddressService::getAddress()
{
    CLIENT* cl;
    int* address;

    cl = AgentAddressService::createClient();

    //Call the remote procedure "resolve_1" on the server
    address = getaddress_1( NULL, cl );

    //An error occurred while calling the server.
    if ( address == NULL )
        throw Exception( clnt_sperror( cl, getServerAddress() ) );

    //Okay, we successfully called the remote procedure.

    //Server was unable to resolve the name
    if ( *address < 0 )
        throw Exception( "Agent Address ERROR: couldn’t get an address	");

    clnt_destroy( cl );

    return *address;
}

int AgentAddressService::resolve( std::string name )
{
    CLIENT* cl;
    int* address;
    /*
     * Create client "handle" used for calling MESSAGEPROG on the
     * server designated on the command line. We tell the RPC package
     * to use the "tcp" protocol when contacting the server.
     */
    cl = clnt_create( getServerAddress(), AGENT_ADDRESS_PROG, AGENT_ADDRESS_VERS, "tcp" );

    // Couldn’t establish connection with server.
    if ( cl == NULL )
        throw Exception( clnt_spcreateerror( getServerAddress() ) );

    //Call the remote procedure "resolve_1" on the server
    char* nameArg = ( char* ) ( name.c_str() );
    address = resolve_address_name_1( &nameArg, cl );

    //An error occurred while calling the server.
    if ( address == NULL )
        throw Exception( clnt_sperror( cl, getServerAddress() ) );

    //Okay, we successfully called the remote procedure.

    //Server was unable to resolve the name
    if ( *address < 0 )
        throw Exception( "Agent Address ERROR: couldn’t resolve the name: " + name );

    clnt_destroy( cl );

    return *address;
}

int AgentAddressService::registerName( std::string name, int address ) {
	return AgentAddressService::registerNameStatic(name, address);
}

int AgentAddressService::registerQueueAgent( std::string queuePath,char queueKey, int mType, int address)
{
	std::stringstream ss;

	ss<<"|"<<queuePath<<"|"<<queueKey<<"|"<<mType<<"|";

	return registerNameStatic(ss.str());
}

int AgentAddressService::resolveQueueAgent( std::string queuePath,char queueKey, int mType)
{
	std::stringstream ss;

	ss<<"|"<<queuePath<<"|"<<queueKey<<"|"<<mType<<"|";

	return resolve(ss.str());
}

std::string AgentAddressService::resolveNameById(int agentName)
{
    CLIENT* cl;
    char ** result;

    cl = AgentAddressService::createClient();

    //Call the remote procedure "resolve_1" on the server

    result = getagentbyid_1( &agentName, cl );


    // An error occurred while calling the server.
    //Print error message and die.
    if ( result == NULL )
        throw Exception( clnt_sperror( cl, getServerAddress() ) );

    std::string strResult(*result);

    // Okay, we successfully called the remote procedure.

    clnt_destroy( cl );

    return strResult;

}

int AgentAddressService::registerNameStatic( std::string name, int address )
{
    CLIENT* cl;
    int* result;

    cl = AgentAddressService::createClient();

    //Call the remote procedure "resolve_1" on the server

    std::string addrStr =StringUtils::NumberToString(address);

    dns_record_agent_address record;
    record.name = (char*)name.c_str();
    record.address = (char*)addrStr.c_str();

    result = register_address_name_static_1( &record, cl );

    // An error occurred while calling the server.
    //Print error message and die.
    if ( result == NULL )
        throw Exception( clnt_sperror( cl, getServerAddress() ) );

    // Okay, we successfully called the remote procedure.

    //Server was unable to register the name
    if ( *result < 0 )
        throw Exception( "Agent address ERROR: couldn’t register the name: " + name );

    clnt_destroy( cl );
    return *result;
}

int AgentAddressService::registerNameDynamic( std::string name, int address )
{
    CLIENT* cl;
    int* result;

    cl = AgentAddressService::createClient();

    //Call the remote procedure "resolve_1" on the server

    std::string addrStr =StringUtils::NumberToString(address);

    dns_record_agent_address record;
    record.name = (char*)name.c_str();
    record.address = (char*)addrStr.c_str();

    result = register_address_name_dynamic_1( &record, cl );

    // An error occurred while calling the server.
    //Print error message and die.
    if ( result == NULL )
        throw Exception( clnt_sperror( cl, getServerAddress() ) );

    // Okay, we successfully called the remote procedure.

    //Server was unable to register the name
    if ( *result < 0 )
        throw Exception( "Agent address ERROR: couldn’t register the name: " + name );

    clnt_destroy( cl );
    return *result;
}

void AgentAddressService::unregister( std::string name )
{
    CLIENT* cl;

    int* status;
    cl = AgentAddressService::createClient();

    // Call the remote procedure "resolve_1" on the server
    char* nameArg = ( char* ) ( name.c_str() );
    status = unregister_address_name_1( &nameArg, cl );

    //An error occurred while calling the server.
    if ( status == NULL )
        throw Exception( clnt_sperror( cl, getServerAddress() ) );

    //Okay, we successfully called the remote procedure.

    //Server was unable to resolve the name
    if ( *status < 0 )
        throw Exception( "Agent address ERROR: couldn’t unregister the name: " + name );

    clnt_destroy( cl );
}

}//end namespace channel
